﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Collections;
using System.Linq;
using Noris.Schedule.Support;
using Noris.Schedule.Support.Services;

namespace Noris.Schedule.UI.Components
{
	// CLASS GridGraphCls : BLOK METOD PRO PODPORU MEZIGRAFOVÉ AKTIVITY
	/// <summary>
	/// Třída pro zobrazování grafu některého typu v rámci gridu
	/// </summary>
	// ŘEŠENÉ OBLASTI : MEZIGRAFOVÁ AKTIVITA VE SPOLUPRÁCI S DATOVOU VRSTVOU
	internal partial class GridGraphCls : DblGraphControl, ILeaveFocus
	{
		#region PROVÁZÁNÍ EVENTŮ DATA => GRAPH
		/// <summary>
		/// do GridData zaregistruje handlery eventů = this metody,
		/// pro obsluhu události které mohou jít do DataSource
		/// </summary>
		private void _EventPrepare()
		{
			// Toto jsou eventy v datech (GridData), odkud dochází k volání handlerů v GridGraph (this):
			this._GridData.EditorDataChangingEvnt += new EditorDataChangeHandler(_GridData_EditorDataChanging);
			this._GridData.EditorDataChangedEvnt += new EditorDataChangeHandler(_GridData_EditorDataChanged);
            this._GridData.FunctionDataChangedEvnt += new EditorDataChangeHandler(_GridData_FunctionDataChangedEvnt);
		}
		#endregion
		#region EVENTY, METODY PRO STRANU this (u nás došlo k akci, voláme reakci jinam, nahoru = do Multiplexoru)
		/// <summary>
		/// Event po změně aktivního řádku
		/// </summary>
		[Description("Event po změně aktivního řádku")]
		[Category("Action")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		public event GridGraphEventHandler RowChangedAfter;
		/// <summary>
		/// Invoker eventu RowChangedAfter
		/// </summary>
		protected void OnRowChangedAfter()
		{
			if (this.RowChangedAfter != null)
			{
				GridGraphEventArgs args = this.CreateGraphEvent(GraphEventType.RowEnter, this._ActiveRowIdx, this.CurrentDataRow);
				if (args != null)
				{
					// Využívám objektu DoOn, který zajistí provedení akce na počátku a na konci svého života, včetně případného výskytu chyby (tj. i po chybě provede svoji předepsanou koncovou akci):
					using (DoOn.BeginEnd(delegate { this._IntergraphSkipOtherActivity = true; }, delegate { this._IntergraphSkipOtherActivity = false; }))
					{
						this.RowChangedAfter(this, args);      // Typicky se vyvolá metoda GraphMultiplexCls._GraphRowChangedAfter()
					}
				}
			}
		}
		/// <summary>
		/// Event vyvolaný po aktivaci grafického elementu, poté kdy jsou rozsvíceny vztahy tohoto elementu.
		/// Umožní se tak, aby vedlejší graf rozsvítil odpovídající záznamy.
		/// </summary>
		[Description("Event vyvolaný po aktivaci grafického elementu, poté kdy jsou rozsvíceny vztahy tohoto elementu.")]
		[Category("Action")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		public event GridGraphEventHandler GraphElementClick;
		/// <summary>
		/// Invoker eventu GraphElementClick.
		/// Pokud je graf standardně hostován v panelu v rámci multiplexoru, 
		/// pak tento event proběhne skrz multiplexor do všech ostatních grafů (kromě tohoto, detekováno podle SourceGraphID)
		/// a je vyvolána metoda GraphElementOtherClicked(object sender, GridGraphEventArgs e).
		/// Touto cestou si grafy mezi sebou předávají inforomaci o události Click
		/// </summary>
		protected void OnGraphElementClick(GridMouseTargetCls target)
		{
			if (this.GraphElementClick != null)
			{
				GridGraphEventArgs args = this.CreateGraphEvent(GraphEventType.MouseClick, target);
				if (args != null)
				{
					// Využívám objektu DoOn, který zajistí provedení akce na počátku a na konci svého života, včetně případného výskytu chyby (tj. i po chybě provede svoji předepsanou koncovou akci):
					using (DoOn.BeginEnd(delegate { this._IntergraphSkipOtherActivity = true; }, delegate { this._IntergraphSkipOtherActivity = false; }))
					{
						this.GraphElementClick(this, args);    // Typicky se vyvolá metoda GraphMultiplexCls._GraphElementClick()
					}
				}
			}
		}
		/// <summary>
		/// Příznak (true), že právě nyní probíhá taková mezigrafová akce, která potlačuje reakci na událost RowChange na jiném grafu.
		/// </summary>
		/// <remarks>
		/// Vysvětlení, příklad:
		/// Mějme graf A, na kterém jsme kliknuli na element A1. Dojde k vyvolání aktivity: this.OnGraphElementClick() - grafB.GraphElementOtherClicked(),
		/// a v grafu B se najde řádek, který odpovídá aktivnímu elementu z našeho grafu A. Tento řádek se aktivuje.
		/// Tím dojde ke změně řádku na grafu B, což vyvolá tuto aktivitu: grafB.OnRowChangedAfter() - this.RowOtherChanged().
		/// Náš graf by měl reagovat tak, že vyhledá odpovídající řádek / elementy, ale tím se degraduje prvotní akce uživatele (kliknul na nějaký element).
		/// Je tedy třeba potlačit naši reakci (v metodě this.RowOtherChanged()).
		/// Jíné grafy mohou reagovat, ale my ne.
		/// </remarks>
		private bool _IntergraphSkipOtherActivity;
		/// <summary>
		/// Event vyvolaný po doubleclicku na některém grafu.
		/// Umožní se tak, aby vedlejší graf aktivoval odpovídající řádek, a případně i stránku, na které je obsažen.
		/// </summary>
		[Description("Event vyvolaný po doubleclicku na některém grafu.")]
		[Category("Action")]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Browsable(true)]
		public event GridGraphEventHandler GraphRowDoubleClick;
		/// <summary>
		/// Invoker eventu GraphRowDoubleClick.
		/// Pokud je graf standardně hostován v panelu v rámci multiplexoru, 
		/// pak tento event proběhne skrz multiplexor do všech ostatních grafů (kromě tohoto, detekováno podle SourceGraphID)
		/// a je vyvolána metoda GraphRowOtherDoubleClicked(object sender, GridGraphEventArgs e).
		/// Touto cestou si grafy mezi sebou předávají inforomaci o události Click
		/// </summary>
		/// <param name="rowIndex">Index řádku</param>
		/// <param name="rowDataLine">Data o řádku</param>
		protected void OnGraphRowDoubleClick(GridMouseTargetCls target)
		{
			if (this.GraphRowDoubleClick != null && target.RowDataLine != null)
			{
				GridGraphEventArgs args = this.CreateGraphEvent(GraphEventType.MouseDoubleClick, target);
				if (args != null)
				{
					// Využívám objektu DoOn, který zajistí provedení akce na počátku a na konci svého života, včetně případného výskytu chyby (tj. i po chybě provede svoji předepsanou koncovou akci):
					using (DoOn.BeginEnd(delegate { this._IntergraphSkipOtherActivity = true; }, delegate { this._IntergraphSkipOtherActivity = false; }))
					{
						this.GraphRowDoubleClick(this, args);  // Typicky se vyvolá metoda GraphMultiplexCls._GraphRowDoubleClick()
					}
				}
			}
		}
		/// <summary>
		/// Event při události, kdy v datech dochází ke změně dat, a změna nadále probíhá
		/// </summary>
		[Description("Event při události, kdy v datech dochází ke změně dat, a změna nadále probíhá")]
		[Category("Action")]
		public event EditorDataChangeHandler EditorDataChanging;
		/// <summary>
		/// Handler, kdy GridDataCls (podřízená datová třída) vyvolává svůj event EditorDataChanging, 
		/// zde v GridGraphCls jej obsloužíme a posíláme do našeho eventu EditorDataChanging:
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="args">Data popisující změnu</param>
		void _GridData_EditorDataChanging(object sender, GridDataEventArgs args)
		{
			if (this.EditorDataChanging != null)
			{
				this.EditorDataChanging(sender, args);        // Typicky se vyvolá metoda GraphMultiplexCls._EditorDataChanging()
			}
		}
		/// <summary>
		/// Event při události, kdy v datech dochází ke změně dat, a změna právě skončila
		/// </summary>
		[Description("Event při události, kdy v datech dochází ke změně dat, a změna právě skončila")]
		[Category("Action")]
		public event EditorDataChangeHandler EditorDataChanged;
		/// <summary>
		/// Handler, kdy GridDataCls (podřízená datová třída) vyvolává svůj event EditorDataChanged, 
		/// zde v GridGraphCls jej obsloužíme a posíláme do našeho eventu EditorDataChanged:
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="args">Data popisující změnu</param>
		void _GridData_EditorDataChanged(object sender, GridDataEventArgs args)
		{
			if (this.EditorDataChanged != null)
			{
				this.EditorDataChanged(sender, args);          // Typicky se vyvolá metoda GraphMultiplexCls._EditorDataChanged()
			}
		}
		/// <summary>
		/// Event při události, kdy skončila funkce, která mění data.
		/// </summary>
        [Description("Event při události, kdy skončila funkce, která mění data")]
        [Category("Action")]
        public event EditorDataChangeHandler FunctionDataChanged;
        /// <summary>
        /// Handler, kdy GridDataCls (podřízená datová třída) skončila funkci, která mění data - volá svůj event EditorDataChanged, 
        /// zde v GridGraphCls jej obsloužíme a posíláme do našeho eventu FunctionDataChanged:
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">Data popisující změnu</param>
        void _GridData_FunctionDataChangedEvnt(object sender, GridDataEventArgs args)
        {
            if (this.FunctionDataChanged != null)
			{
                this.FunctionDataChanged(sender, args);         // Typicky se vyvolá metoda GraphMultiplexCls._FunctionDataChanged()
			}
        }


        /// <summary>
        /// Event vyvolaný v situaci, kdy tento graf (typicky vlivem interaktivní funkce) požaduje reload všech dat na všech grafech.
        /// Tento event typicky obsluhuje multiplexor a řízení přechází do metody .
        /// </summary>
        [Description("Event vyvolaný v situaci, kdy tento graf (typicky vlivem interaktivní funkce) požaduje reload všech dat na všech grafech.")]
        [Category("Action")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Browsable(true)]
        public event GridGraphEventHandler RequestReloadAllRows;
        /// <summary>
        /// Invoker eventu RequestReloadAllRows.
        /// Pokud je graf standardně hostován v panelu v rámci multiplexoru, 
        /// pak tento event proběhne skrz multiplexor do všech ostatních grafů (kromě tohoto, detekováno podle SourceGraphID)
        /// a je vyvoláno přenačtení všech dat grafů.
        /// </summary>
        protected void OnRequestReloadAllRows()
        {
            if (this.RequestReloadAllRows != null)
            {
                GridGraphEventArgs args = this.CreateGraphEvent(GraphEventType.ReloadAllRows);
                if (args != null)
                {
                    // Využívám objektu DoOn, který zajistí provedení akce na počátku a na konci svého života, včetně případného výskytu chyby (tj. i po chybě provede svoji předepsanou koncovou akci):
                    using (DoOn.BeginEnd(delegate { this._IntergraphSkipOtherActivity = true; }, delegate { this._IntergraphSkipOtherActivity = false; }))
                    {
                        this.RequestReloadAllRows(this, args);  // Typicky se vyvolá metoda GraphMultiplexCls._RequestReloadAllRows()
                    }
                }
            }
        }

		#endregion
		#region REAKCE - JINÝ GRAF PROVEDL AKCI, NÁŠ GRAF NA NI REAGUJE
		/// <summary>
		/// Příjemce události, kdy jiný graf zaregistroval změnu řádku, a tento graf na to může reagovat.
		/// Pokud chce, může tento graf aktivovat odpovídající řádek, může si zobrazit svoje vztahy blízké vztahům ze zdrojového grafu.
		/// Tuto metodu volá systém i při zhasnutí vztahů na zdrojovém grafu, aby tento (this) graf mohl zhasnout svoje vztahy.
		/// Viditelnost vztahů ve zdrojovém grafu je uvedena v e.RelationVisible.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		internal void RowOtherChanged(object sender, GridGraphEventArgs e)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			if (!this._CurrentGraphActivityBegin(e, out activityMode)) return;

			// Specifická reakce tohoto grafu:
			if (e.SourceRowGId.IsEmpty) return;                   // Nelze určit zdrojový řádek => skončíme.

			// Pokusíme se najít ekvivalent k řádku a elementu, který je předán:
			this._CrossGraphCurrentShow(e, activityMode);
		}
		/// <summary>
		/// Příjemce události, kdy jiný graf edituje svoje data, editace stále probíhá, a tento graf na to může reagovat.
		/// Tuto cestu zajišťuje typicky Multiplexor: vytváří handler pro event this.EditorDataChanging, 
		/// a tuto událost posílá do všech grafů do metody this.EditorDataOtherChanging()
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		internal void EditorDataOtherChanging(object sender, GridDataEventArgs e)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			if (!this._CurrentGraphActivityBegin(e, out activityMode)) return;

			// Specifická reakce tohoto grafu:
			if (e.ChangedRows == null || e.ChangedRows.Count == 0) return;

			this._CrossDataCurrentShow(e, activityMode);
			// this._GridData.EditorDataOtherChanging(e);
		}
		/// <summary>
		/// Příjemce události, kdy jiný graf editoval svoje data, dokončil editaci, a tento graf na to může reagovat.
		/// Tuto cestu zajišťuje typicky Multiplexor: vytváří handler pro event this.EditorDataChanged,
		/// a tuto událost posílá do všech grafů do metody this.EditorDataOtherChanged()
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		internal void EditorDataOtherChanged(object sender, GridDataEventArgs e)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			if (!this._CurrentGraphActivityBegin(e, out activityMode)) return;

			// Specifická reakce tohoto grafu: pokud nejsou změny, nic neřešíme:
			if ((e.ChangedRows == null || e.ChangedRows.Count == 0) && !e.LinkListChanged) return;

			this._CrossDataCurrentShow(e, activityMode);
			// this._GridData.EditorDataOtherChanged(e);
		}
        /// <summary>
		/// Příjemce události, kdy jiný graf spustil funkci, která mění data, a tento graf na to může reagovat.
		/// Tuto cestu zajišťuje typicky Multiplexor: vytváří handler pro event this.FunctionDataChanged,
		/// a tuto událost posílá do všech grafů do metody this.FunctionDataOtherChanged()
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
        internal void FunctionDataOtherChanged(object sender, GridDataEventArgs e)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			if (!this._CurrentGraphActivityBegin(e, out activityMode)) return;

			// Specifická reakce tohoto grafu: pokud nejsou změny, nic neřešíme:
			if ((e.ChangedRows == null || e.ChangedRows.Count == 0) && !e.LinkListChanged) return;

			this._CrossDataCurrentShow(e, activityMode);
			// this._GridData.EditorDataOtherChanged(e);
		}
        /// <summary>
		/// Příjemce události, kdy jiný graf zaregistroval kliknutí na element, a tento graf na to může reagovat.
		/// Pokud chce, může tento graf aktivovat odpovídající řádek, může si zobrazit svoje vztahy blízké vztahům ze zdrojového grafu.
		/// Tuto metodu volá systém i při zhasnutí vztahů na zdrojovém grafu, aby tento (this) graf mohl zhasnout svoje vztahy.
		/// Viditelnost vztahů ve zdrojovém grafu je uvedena v e.RelationVisible.
		/// Při ukončení viditelnosti vztahů (kliknutím do prázdné plochy) se vyvolává opět tato metoda, 
		/// ale má e.DataElement = null i e.DataRow == null,
		/// a má e.RelationVisible = false.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		internal void GraphElementOtherClicked(object sender, GridGraphEventArgs e)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			if (!this._CurrentGraphActivityBegin(e, out activityMode)) return;

			// Specifická reakce tohoto grafu:
			if (e.DataElement == null) return;                    // Nelze určit zdrojový element => skončíme.

			// Pokusíme se najít ekvivalent k řádku a elementu, který je předán:
			this._CrossGraphCurrentShow(e, activityMode);
		}
		/// <summary>
		/// Příjemce události, kdy jiný graf zaregistroval doubleclick na řádek, a tento graf na to může reagovat.
		/// Pokud chce, může tento graf aktivovat odpovídající řádek, může si zobrazit svoje vztahy blízké vztahům ze zdrojového grafu.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		internal void GraphRowOtherDoubleClicked(object sender, GridGraphEventArgs e)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			if (!this._CurrentGraphActivityBegin(e, out activityMode)) return;

			// Specifická reakce tohoto grafu:
			if (e.DataRow == null) return;

			// Pokusíme se najít ekvivalent k řádku a elementu, který je předán:
			this._CheckFirstDataLoad();                           // V případě potřeby si zajistí načtení první dávky dat (řádky)
			this._CrossGraphCurrentShow(e, activityMode);
		}
		/// <summary>
		/// Příjemce události, kdy došlo ke změně viditelnosti tohoto grafu (aktivace / deaktivace záložky s grafem).
		/// Pokud byl graf (jeho stránka) viditelný, a nyní se graf zhasíná, pak je parametr isVisible = false.
		/// Pokud byl graf (jeho stránka) neviditelný, a nyní se graf aktivuje, pak je parametr isVisible = true.
		/// </summary>
		/// <param name="isVisible"></param>
		internal void GraphVisibleChanged(bool isVisible)
		{
			// Začátek: pokud mám být neaktivní, skončím hned:
			CurrentGraphCrossActivityMode activityMode;
			GraphEventType eventType = (isVisible ? GraphEventType.PageActivated : GraphEventType.PageDeactivated);
			if (!this._CurrentGraphActivityBegin(eventType, out activityMode)) return;

			// Prvotní test, zda mám reagovat na změnu PageActivate :
			if (activityMode == CurrentGraphCrossActivityMode.None) return;

			// Specifická reakce tohoto grafu:
			GridGraphEventArgs e = new GridGraphEventArgs(eventType);
			this._CrossGraphCurrentShow(e, activityMode);
		}
		#endregion
		#region PRIVÁTNÍ SPOLEČNÉ METODY PRO ŘÍZENÍ AKTIVITY CURRENT GRAFU PODLE UDÁLOSTI NA SOURCE GRAFU
		/// <summary>
		/// Zahájí první kroky k řešení aktivity grafu this (slave) po akci grafu Source (daný v parametru e).
		/// Pokud tento graf nemá být aktivní, vrátí false.
		/// 
		/// </summary>
		private bool _CurrentGraphActivityBegin(GridEventArgs e, out CurrentGraphCrossActivityMode activityMode)
		{
			return this._CurrentGraphActivityBegin(e.EventType, out activityMode);
		}
		/// <summary>
		/// Zahájí první kroky k řešení aktivity grafu this (slave) po akci grafu Source (daný v parametru e).
		/// Pokud tento graf nemá být aktivní, vrátí false.
		/// </summary>
		private bool _CurrentGraphActivityBegin(GraphEventType eventType, out CurrentGraphCrossActivityMode activityMode)
		{
			activityMode = CurrentGraphCrossActivityMode.None;

			// Pokud mám potlačenou reakci na akce z jiného grafu, pak vrátím false:
			if (this._IntergraphSkipOtherActivity) return false;

			// Režim aktivity tohoto grafu, v případě události daného druhu na jiném grafu:
			activityMode = this._GridData.CrossGraphGetCurrentMode(eventType);

			// Pokud jde o event PageActivate, pak netestuji Visible (to se řeší jinde), a naše this.Visible by ovlivnilo výsledky testu:
			if (eventType == GraphEventType.PageSwitch)
				return true;

			// Pokud mám být neaktivní v případě, že nejsem vidět, pak skončím hned:
			bool inactiveWhenInvisible = ((activityMode & CurrentGraphCrossActivityMode.InactiveWhenInvisible) > 0);
			if (inactiveWhenInvisible && !this.Visible) return false;   // Pokud mám být potichu, když nejsem vidět, a nejsem vidět, tak skončíme.

			return true;
		}
		/// <summary>
		/// Skryje vztahy v this grafu, pokud jsou skryté v source grafu
		/// </summary>
		/// <param name="args"></param>
		private void _CurrentGraphActivityHideRelations(GridGraphEventArgs args)
		{
			if (args != null && this._EditedRelationVisible && !args.RelationVisible)
			{
				this._EditorRelationsClear(true);
				this._EditedElementTable.Clear();
			}
		}
		/// <summary>
		/// Tato metoda realizuje aktivitu current grafu jako reakci na událost v jiném grafu / v okně.
		/// Pokusí se najít patřičnou odpověď (response) a provést předepsané operace
		/// (aktivovat řádek a element(y) v tomto grafu, které odpovídají řádku a elementu předaném z jiného grafu.)
		/// Jde o mezigrafovou aktivitu.
		/// </summary>
		/// <param name="e"></param>
		/// <param name="activityMode">Druh aktivity, která vede k této akci</param>
		private void _CrossGraphCurrentShow(GridGraphEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			// Získám podklady pro reakci tohoto grafu na změnu v source grafu:
			InterGraphCurrentResponseCls response = this._GridData.CrossGraphFindData(e, activityMode);
			if (response == null) return;

			// Vyřešíme řádky (na datové úrovni) = smazání, načtení, převzetí z response:
			this._GridData.CrossGraphDataResponseRows(response);

			// Vyřešíme elementy = selectování elementů a určení prvního řádku se selectovaným elementem (do response.ActiveRowIndex)
			if (this._EditedElementTable == null)
				this._EditedElementTable = new Dictionary<GID, GID>();
			this._GridData.CrossGraphResponseElements(e, activityMode, response, ref this._EditedElementTable);

            // Vyřešíme Filter:
            this._CrossGraphCurrentFilter(e, response);

            // Vyřešíme RelationNet:
			this._CrossGraphCurrentRelationNet(e, response);

			// Aktivovat nalezený řádek:
			this._CurrentGraphActivateRow(response);

			// Aktivovat graf:
			if (e.EnabledPageAction && response.ActiveRowIndex >= 0)
			{	// Pokud jsem našel řádek, pak je reakce závislá i na deklaraci aktivity this grafu:
				//  Rozsvítit stránku:
				if (response.IsActiveFor(CurrentGraphCrossActivityMode.ActivateGraphPage))
					e.ResponseShowAcceptGraph = true;

				//  Zastavit proces předávání eventu do dalších grafů:
				if (response.IsActiveFor(CurrentGraphCrossActivityMode.StopProcess))
					e.ResponseAcceptGraphId = this.GraphID;      // Tímto ukončím zpracování eventu v jiných grafech. Já jsem ten graf, který událost zpracoval.
			}

			this.Draw();
		}
		/// <summary>
		/// Vyřeším zobrazení / zhasnutí sítě vztahů v Current grafu podle dat v Source grafu a v response
		/// </summary>
		/// <param name="e"></param>
		/// <param name="response"></param>
		private void _CrossGraphCurrentRelationNet(GridGraphEventArgs e, InterGraphCurrentResponseCls response)
		{
			if (this._EditedRelationVisible)
				this._EditorRelationsClear(false);

			// Pokud aktivita předepisuje zobrazení vztahů:
			if (response.IsActiveFor(CurrentGraphCrossActivityMode.ShowRelationNet))
			{

			}
		}
		/// <summary>
		/// Vyřeším aktivaci / deaktivaci aplikačního filtru v Current grafu podle dat v Source grafu a v response
		/// </summary>
		/// <param name="e"></param>
		/// <param name="response"></param>
		private void _CrossGraphCurrentFilter(GridGraphEventArgs e, InterGraphCurrentResponseCls response)
		{
			// Má proběhnout aktivace filtru na mém grafu podle výsledků (typicky z datového zdroje mého grafu)?
            if (response.ResultRowFilterList != null)
                this.AcceptRowExplicitFilter(response.ResultRowFilterList, true);
 		}
		/// <summary>
		/// Tato metoda se pokusí najít a aktualizovat řádky a element(y) v tomto grafu, které odpovídají editovaným datům.
		/// Jde o mezigrafovou aktivitu.
		/// </summary>
		/// <param name="e"></param>
		/// <param name="activityMode">Druh aktivity, která vede k této akci</param>
		private void _CrossDataCurrentShow(GridDataEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			// Získám podklady pro reakci tohoto grafu na změnu v source grafu:
			InterGraphCurrentResponseCls response = this._GridData.CrossDataFindData(e, activityMode);
			if (response == null) return;

			// Vyřešíme řádky (na datové úrovni) = smazání, načtení, převzetí z response:
			this._GridData.CrossGraphDataResponseRows(response);

			// Aktivovat nalezený řádek:
			this._CurrentGraphActivateRow(response);
		}
		/// <summary>
		/// Aktivuje řádek current grafu podle odpovědi v response.
		/// Testuje aktivitu (kde musí být aktivace řádku povolena hodnotou ActivateFirstEqualRow), 
		/// a testuje index řádku response.ActiveRowIndex
		/// </summary>
		/// <param name="response"></param>
		private void _CurrentGraphActivateRow(InterGraphCurrentResponseCls response)
		{
			if (response.ActiveRowIndex >= 0 && response.IsActiveFor(CurrentGraphCrossActivityMode.ActivateFirstEqualRow))
				// Aktivovat nalezený řádek:
				this._ActivateRow(response.ActiveRowIndex, false, true, true);
		}
		#endregion
		#region TVORBA EVENTARGS GridGraphEventArgs
		/// <summary>
		/// Vytvoří a vrátí EventArgs pro daný typ eventu.
		/// Do EventArgs opíše definici tohoto grafu a režim vyvolání akce pro tento event.
		/// Pokud vrátí null, pak se tento typ eventu nemá obsluhovat (což je definováno v deklaraci grafu).
		/// </summary>
		/// <param name="graphEvent">Druh eventu. Vloží se do argumentu, a podle něj se vybere odpovídající režim aktivity z this.GraphDeclarationData.</param>
		/// <param name="target">Data o řádku a elementu, na který ukázala myš.</param>
		/// <returns></returns>
		protected GridGraphEventArgs CreateGraphEvent(GraphEventType graphEvent, GridMouseTargetCls target)
		{
			GridGraphEventArgs args = this.CreateGraphEvent(graphEvent);
			if (args == null) return null;

			if (target != null)
			{
				args.RowIndex = target.RowIndex;
				if (target.ItemElement != null)
					args.DataElement = target.ItemElement.DataElement;
				if (target.RowDataLine != null)
					args.DataRow = target.RowDataLine.DataRow.RowItem;
			}

			return args;
		}
		/// <summary>
		/// Vytvoří a vrátí EventArgs pro daný typ eventu.
		/// Do EventArgs opíše definici tohoto grafu a režim vyvolání akce pro tento event.
		/// Pokud vrátí null, pak se tento typ eventu nemá obsluhovat (což je definováno v deklaraci grafu).
		/// </summary>
		/// <param name="graphEvent">Druh eventu. Vloží se do argumentu, a podle něj se vybere odpovídající režim aktivity z this.GraphDeclarationData.</param>
		/// <param name="rowIndex">Index řádku</param>
		/// <param name="dataRow">Data o aktivním řádku.</param>
		/// <returns></returns>
		protected GridGraphEventArgs CreateGraphEvent(GraphEventType graphEvent, int rowIndex, GridDataRowCls dataRow)
		{
			GridGraphEventArgs args = this.CreateGraphEvent(graphEvent);
			if (args == null) return null;

			args.RowIndex = rowIndex;
			args.DataRow = (dataRow == null ? null : dataRow.RowItem);

			return args;
		}
		/// <summary>
		/// Vytvoří a vrátí EventArgs pro daný typ eventu.
		/// Do EventArgs opíše definici tohoto grafu a režim vyvolání akce pro tento event.
		/// Pokud vrátí null, pak se tento typ eventu nemá obsluhovat (což je definováno v deklaraci grafu).
		/// </summary>
		/// <param name="graphEvent">Druh eventu. Vloží se do argumentu, a podle něj se vybere odpovídající režim aktivity z this.GraphDeclarationData.</param>
		/// <returns></returns>
		protected GridGraphEventArgs CreateGraphEvent(GraphEventType graphEvent)
		{
			TargetGraphCrossActivityMode targetMode = this._GridData.CrossGraphGetTargetMode(graphEvent);
			if (targetMode == TargetGraphCrossActivityMode.None)
				return null;

			GridGraphEventArgs args = new GridGraphEventArgs(this.GraphID, this.FirstGIdToLoad, this.DefaultGraphType, graphEvent, targetMode);
			args.RelationVisible = this._EditedRelationVisible;
			return args;
		}
		#endregion
    }
	// CLASS GridDataCls : BLOK METOD PRO PODPORU MEZIGRAFOVÉ AKTIVITY
	/// <summary>
	/// Data, na kterých stojí Grid + Tree
	/// </summary>
	/// <remarks>
	/// Logika věcí:
	/// GridGraphCls je vizální prvek. Je úkoly jsou:
	/// - hraje roli vizuálního prvku na formuláři
	/// - zajistí zobrazování dat: tj. řádky, Paint, ikony, labely, rámečky a šipky grafů.
	/// -- zobrazování řeší ve spolupráci s datovou vrstvou, která si do sebe ukládá aktuální pozice (Rectangle) jednotlivých oblastí
	/// - dále přebírá eventy od uživatele (Mouse, Key, Scroll, ...).
	/// -- tyto eventy řeší ve spolupráci s datovou vrstvou, protože ta detekuje, který datový objekt odpovídá které vizuální oblasti
	/// - prvotní načtení dat je iniciováno z formuláře, vyvoláním metody ReadFirstData
	/// - aby mohl správně zobrazovat konkrétní data, musí GridGraphCls vytovřit datovou vrstvu, kterou je GridDataCls
	/// - při vytváření instance GridDataCls je tato datová instance napojena 
	/// -- jak na vizuální prvek (GridGraphCls), který data zobrazuje
	/// -- tak na konkrétní metodu zdroje vlastních dat, která dodává potřebná data.
	/// - 
	/// GridDataCls je datový prvek, který sám nezobrazuje data, ale umí je načítat, uchovávat, vyhledávat
	/// a umí zajišťovat jejich vyhledání a logickou správu. Jeho úkoly:
	/// - načíst seznam dat do své paměti
	/// - umožnit přístup k datům jako ke stromu, ne jen lineárně
	/// - donačítat další data na požádání
	/// - načtená data transformovat pro jejich zobrazení v navázaném GridGraphCls, vkládat do Gridu nové řádky (Add / Insert)
	/// - spolupracovat na vykreslování dat, protože součástí uložených dat je i informace o vizuálních pozicích prvků
	/// - vyhledávat pro danou vizuální adresu odpovídající logický prvek, tím podporuje interaktivitu gridu.
	/// 
	/// GridDataCls je partial na části:
	///  GridData.cs = základní funkce spojené se správou dat
	///  GridData_editing.cs = funkce spojené s editováním dat
	/// </remarks>
	// ŘEŠENÉ OBLASTI : MEZIGRAFOVÁ AKTIVITA VE SPOLUPRÁCI S VIZUÁLNÍ VRSTVOU
	internal partial class GridDataCls
	{
		#region EVENTY, METODY PRO STRANU this (u nás došlo k akci, voláme reakci jinam, nahoru = typicky do GridGraph)
		/// <summary>
		/// Event při události, kdy v datech dochází ke změně dat, a změna nadále probíhá
		/// </summary>
		[Description("Event při události, kdy v datech dochází ke změně dat, a změna nadále probíhá")]
		[Category("Action")]
		internal event EditorDataChangeHandler EditorDataChangingEvnt;
		/// <summary>
		/// Invoker eventu EditorDataChanging
		/// </summary>
		protected virtual void OnEditorDataChanging(GridEditingChangeMode changeMode)
		{
			if (this.EditorDataChangingEvnt != null)
			{
				GridDataEventArgs args = this.CreateDataEvent(GraphEventType.DataChanged, changeMode);
				if (args != null)
					this.EditorDataChangingEvnt(this, args);      // Typicky se volá metoda GridGraphCls._GridData_EditorDataChanging()
			}
		}
		/// <summary>
		/// Event při události, kdy v datech dochází ke změně dat, a změna právě skončila
		/// </summary>
		[Description("Event při události, kdy v datech dochází ke změně dat, a změna právě skončila")]
		[Category("Action")]
		internal event EditorDataChangeHandler EditorDataChangedEvnt;
		/// <summary>
		/// Invoker eventu EditorDataChanged.
		/// Je internal, může se volat i z vizuální vrstvy.
		/// </summary>
		/// <param name="changeMode">Režim změny</param>
		/// <param name="changedRows">Seznam změněných řádků</param>
		/// <param name="linkListChanged">Příznak změny linků</param>
		internal virtual void OnEditorDataChanged(GridEditingChangeMode changeMode, List<GID> changedRows, bool linkListChanged)
		{
			if (this.EditorDataChangedEvnt != null)
			{
				GridDataEventArgs args = this.CreateDataEvent(GraphEventType.DataChanged, changeMode, changedRows, linkListChanged);
				if (args != null)
					this.EditorDataChangedEvnt(this, args);      // Typicky se volá metoda GridGraphCls._GridData_EditorDataChanged()
			}
		}
        /// <summary>
        /// Event při události, kdy doběhla nějaká funkce a je třeba reagovat na změny dat, které funkce hlásí
        /// </summary>
        [Description("Event při události, kdy doběhla nějaká funkce a je třeba reagovat na změny dat, které funkce hlásí")]
        [Category("Action")]
        internal event EditorDataChangeHandler FunctionDataChangedEvnt;
        /// <summary>
        /// Invoker eventu FunctionDataChangedEvnt.
        /// Je internal, může se volat i z vizuální vrstvy.
        /// </summary>
        /// <param name="changeMode">Režim změny</param>
        /// <param name="changedRows">Seznam změněných řádků</param>
        /// <param name="linkListChanged">Příznak změny linků</param>
        internal virtual void OnFunctionDataChangedEvnt(GridEditingChangeMode changeMode, FunctionMenuItemRunArgs runArgs)
        {
            if (this.FunctionDataChangedEvnt != null)
            {
                GridDataEventArgs args = this.CreateDataEvent(GraphEventType.FunctionChanged, changeMode, runArgs);
                if (args != null)
                    this.FunctionDataChangedEvnt(this, args);    // Typicky se volá metoda GridGraphCls._GridData_FunctionDataChangedEvnt()
            }
        }
        #endregion
		#region REAKCE - JINÝ GRAF PROVEDL AKCI, NÁŠ GRAF NA NI REAGUJE
		/// <summary>
		/// Vedlejší graf právě edituje svoje data. Zdejší graf na to může reagovat.
		/// </summary>
		/// <param name="e"></param>
		internal void EditorDataOtherChanging(GridDataEventArgs e)
		{ }
		/// <summary>
		/// Vedlejší graf právě dokončil editaci svých dat. Zdejší graf na to může reagovat.
		/// </summary>
		/// <param name="e"></param>
		internal void EditorDataOtherChanged(GridDataEventArgs e)
		{
			//this._DataChangedAfter(e);
		}
		#endregion
		#region MEZIGRAFOVÁ KOMUNIKACE - ŘÍZENÍ : HLEDÁNÍ RESPONSE PRO DANOU SITUACI, podle datového zdroje, podle řádku, podle elementu
		/// <summary>
		/// Metoda určí odpovídající reakci grafu this na událost z grafu Source, danou argumentem e.
		/// </summary>
		/// <param name="e">Data o zdroji aktivity (graf, kde se něco stalo, a element + řádek)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		internal InterGraphCurrentResponseCls CrossGraphFindData(GridGraphEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			// Režim: co má tento graf dělat poté, kdy jiný graf zaregistroval určitý event a posílá jej "kolem dokola"?
			if (activityMode == CurrentGraphCrossActivityMode.None) return null;

			// Tento graf má nějak reagovat:
			if ((activityMode & CurrentGraphCrossActivityMode.FindByDataSource) > 0)
				// Máme volat datový zdroj:
				return this._FindThisGraphResponseByDataSource(e, activityMode);
			else if ((activityMode & CurrentGraphCrossActivityMode.FindEqualRow) > 0)
				// Máme najít náš řádek podle shody GIDu řádku this a source:
				return this._FindThisGraphResponseByRow(e, activityMode);
			else if ((activityMode & CurrentGraphCrossActivityMode.FindEqualElement) > 0)
				// Máme najít elementy a řádky podle shody GIDu elementu this a source:
				return this._FindThisGraphResponseByElement(e, activityMode);

			// Nemáme hledat nic:
			return null;
		}
		/// <summary>
		/// Určí reakci this grafu na událost v source grafu (specifikovaná v argumentu GridGraphEventArgs e).
		/// Využije k tomu request DataSourceRequestType.FindInterGraphTargetData do datového zdroje tohoto grafu.
		/// </summary>
		/// <param name="e">Data o zdroji události (graf a element, kde k události došlo)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisGraphResponseByDataSource(GridGraphEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			DataSourceRequestFindInterGraph request = DataSourceRequestFindInterGraph.CreateFindInterGraphForPointer(this._GraphID, this._GraphDeclarationData, activityMode, e.SourceGraphMode, e.EventType, e.DataRow, e.SourcePointer);
            DataSourceCall.RunRequestSync(this._DataSource, request); // this._DataSource.RunRequestSync(request);

			// Odpověd pro tento graf:
			return InterGraphCurrentResponseCls.CreateFromRequest(activityMode, request);
		}
		/// <summary>
		/// Určí reakci this grafu na událost v source grafu (specifikovaná v argumentu GridGraphEventArgs e).
		/// Najde odpovídající řádek podle jeho GIDu.
		/// </summary>
		/// <param name="e">Data o zdroji události (graf a element, kde k události došlo)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisGraphResponseByRow(GridGraphEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			InterGraphCurrentResponseCls response = null;
			GID rowGId = e.SourceRowGId;
			if (!rowGId.IsEmpty && this._DataDict.ContainsKey(rowGId))  // Pokud na vstupu je uveden GID řádku, a v našem seznamu takový GID máme,
				response = InterGraphCurrentResponseCls.CreateForRow(activityMode, rowGId);

			return response;
		}
		/// <summary>
		/// Určí reakci this grafu na událost v source grafu (specifikovaná v argumentu GridGraphEventArgs e).
		/// Najde pole pointerů na zdejší elementy na základě shodného klíče elementu (GID).
		/// </summary>
		/// <param name="e">Data o zdroji události (graf a element, kde k události došlo)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisGraphResponseByElement(GridGraphEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			InterGraphCurrentResponseCls response = null;
			GID elementGId = e.SourceElementGId;
			if (!elementGId.IsEmpty)
				// Najdu řádky, na nichž je umístěn daný element
				response = InterGraphCurrentResponseCls.CreateForElementList(activityMode, this.FindElementInAllRows(elementGId));

			return response;
		}
		/// <summary>
		/// Metoda určí odpovídající reakci grafu this na událost z grafu Source, danou argumentem e.
		/// </summary>
		/// <param name="e">Data o zdroji aktivity (graf, kde se něco stalo, a element + řádek)</param>
		/// <param name="activityMode">Aktivita this grafu při této události</param>
		/// <returns></returns>
		internal InterGraphCurrentResponseCls CrossDataFindData(GridDataEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			// Režim: co má tento graf dělat poté, kdy jiný graf zaregistroval určitý event a posílá jej "kolem dokola"?
			if (activityMode == CurrentGraphCrossActivityMode.None) return null;

			// Tento graf má nějak reagovat:
			if ((activityMode & CurrentGraphCrossActivityMode.FindByDataSource) > 0)
				// Máme volat datový zdroj:
				return this._FindThisDataResponseByDataSource(e, activityMode);
			else if ((activityMode & CurrentGraphCrossActivityMode.FindEqualRow) > 0)
				// Máme najít náš řádek podle shody GIDu řádku this a source:
				return this._FindThisDataResponseByRow(e, activityMode);
			else if ((activityMode & CurrentGraphCrossActivityMode.FindEqualElement) > 0)
				// Máme najít elementy a řádky podle shody GIDu elementu this a source:
				return this._FindThisDataResponseByElement(e, activityMode);

			// Nemáme hledat nic:
			return null;
		}
		/// <summary>
		/// Určí reakci this grafu na událost typu Editace dat v source grafu (specifikovaná v argumentu GridDataEventArgs e).
		/// Využije k tomu request DataSourceRequestType.FindInterGraphTargetData do datového zdroje tohoto grafu.
		/// </summary>
		/// <param name="e">Data o zdroji události (graf a element, kde k události došlo)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisDataResponseByDataSource(GridDataEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			DataSourceRequestFindInterGraph request = DataSourceRequestFindInterGraph.CreateFindInterGraphForEdit(this._GraphID, this._GraphDeclarationData, activityMode, e.SourceGraphMode, e.EventType, e.ChangeMode, e.ChangedRows);
            DataSourceCall.RunRequestSync(this._DataSource, request); // this._DataSource.RunRequestSync(request);

			// Odpověd pro tento graf:
			return InterGraphCurrentResponseCls.CreateFromRequest(activityMode, request);
		}
		/// <summary>
		/// Určí reakci this grafu na událost typu Editace dat v source grafu (specifikovaná v argumentu GridDataEventArgs e).
		/// Najde řádky, které se mají invalidovat, podle shody GIDu dle pole změněných řádků (e.ChangedRows).
		/// </summary>
		/// <param name="e">Data o zdroji události (graf a element, kde k události došlo)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisDataResponseByRow(GridDataEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			// Přiměřená odpověď (response) je: refreshovat ty řádky, 
			//  které jsou shodné se změněnými řádky ze source grafu:
			return _FindThisDataResponseByRowList(e, activityMode);
		}
		/// <summary>
		/// Určí reakci this grafu na událost typu Editace dat v source grafu (specifikovaná v argumentu GridDataEventArgs e).
		/// Najde řádky, které se mají invalidovat, podle shody GIDu dle pole editovaných elementů.
		/// </summary>
		/// <param name="e">Data o zdroji události (graf a element, kde k události došlo)</param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisDataResponseByElement(GridDataEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
			// Přiměřená odpověď (response) je: refreshovat ty řádky, 
			//  které obsahují elementy z editoru:
			Dictionary<GID, GID> elementDict = e.DataEditor.GetElements();     // Soupis elementů: Key = element, Value = řádek (vše v source grafu)
			List<GID> elementList = new List<GID>(elementDict.Keys);           // Jen elementy

			// Pro každý řádek našeho grafu zjistím, zda obsahuje/neobsahuje některý ze změněných elementů,
			// a pokud obsahuje, tak zařadíme tento řádek do seznamu k invalidaci:
			List<GID> invalidateRows = new List<GID>();
			foreach (GridDataRowCls nodeData in this._DataDict.Values)
			{
				foreach (GID elementGId in elementList)
				{
					if (nodeData.ContainElement(elementGId))
					{
						invalidateRows.Add(nodeData.GId);
						break;
					}
				}
			}
			if (invalidateRows.Count == 0) return null;               // Žádný řádek = žádná práce.

			InterGraphCurrentResponseCls response = InterGraphCurrentResponseCls.Create(activityMode);
			response.ResultRowListChange = RowListChangeMode.InvalidateRowGid;
			response.ResultInvalidateRowList = invalidateRows;
			response.ResultElementLinkListChanged = (invalidateRows.Count > 0);

			return response;
		}
		/// <summary>
		/// Vrátí soupis těch řádků v this grafu, které zde existují, a které jsou předány na vstupu
		/// </summary>
		/// <param name="sourceRows"></param>
		/// <param name="activityMode">Režim aktivity tohoto grafu. Vkládá se do response.ActivityMode.</param>
		/// <returns></returns>
		private InterGraphCurrentResponseCls _FindThisDataResponseByRowList(GridDataEventArgs e, CurrentGraphCrossActivityMode activityMode)
		{
            if (e.ChangedRows == null && e.NewDataRows == null && e.DeletedRows == null) return null;

            InterGraphCurrentResponseCls response = InterGraphCurrentResponseCls.Create(activityMode);

            if (e.ChangedRows != null)
            {
                Dictionary<GID, object> currentGids = new Dictionary<GID, object>();
                foreach (GID rowGId in e.ChangedRows)
                {
                    if (this._DataDict.ContainsKey(rowGId) && !currentGids.ContainsKey(rowGId))
                        currentGids.Add(rowGId, null);
                }
                if (currentGids.Count > 0)
                {
                    response.ResultRowListChange = RowListChangeMode.InvalidateRowGid;
                    response.ResultInvalidateRowList = new List<GID>(currentGids.Keys);
                }
            }

            if (e.NewDataRows != null && e.NewDataRows.Count > 0)
                response.ResultNewDataRowList = new List<IDataRow>(e.NewDataRows);

            if (e.DeletedRows != null && e.DeletedRows.Count > 0)
                response.ResultDeleteRowList = new List<GID>(e.DeletedRows);

            if (response.ResultNewDataRowList == null && response.ResultRowListChange == null && response.ResultDeleteRowList == null)
                return null;

            response.ResultElementLinkListChanged = true;
			return response;
		}
		#endregion
		#region MEZIGRAFOVÁ KOMUNIKACE - ŘÍZENÍ : PROVEDENÍ REAKCE Z RESPONSE DO DAT
		/// <summary>
		/// Podle informací v response zajistí clear / načtení / uložení / refresh řádků do this grafu
		/// </summary>
		/// <param name="response">Data pro řízení odpovědi tohoto grafu</param>
		internal void CrossGraphDataResponseRows(InterGraphCurrentResponseCls response)
		{
			GID firstGId = this.FirstLoadedGId;

			bool invalidateRows = (response.ResultInvalidateRowList != null && (response.IsActiveFor(CurrentGraphCrossActivityMode.InvalidateRows) || response.IsRowChangeMode(RowListChangeMode.InvalidateRowGid)));
			bool linkListChanged = response.ResultElementLinkListChanged;

			// Smazat řádky?
			if (response.IsActiveFor(CurrentGraphCrossActivityMode.ReloadAllRows) || response.IsRowChangeMode(RowListChangeMode.ClearRowList))
			{
				this.Clear();
				// Po clearu už nebudu invalidovat řádky ani linky ! :
				invalidateRows = false;
				linkListChanged = false;
			}

			// Načíst řádky přes request?
			if (response.IsActiveFor(CurrentGraphCrossActivityMode.ReloadAllRows) || response.IsRowChangeMode(RowListChangeMode.CallTopLevelRead))
				this.ReadFirstDataList(firstGId);

			// Invalidovat řádky a nebo shodit linky (tedy, pokud před chvilkou nebyl Clear()):
			if (invalidateRows || linkListChanged)
			{
				List<GID> changedRows = null;
				if (invalidateRows)
					changedRows = this._CrossDataGetInvalidateRows(response);
                this._DataChangedAfter(response.ResultNewDataRowList, changedRows, response.ResultDeleteRowList, linkListChanged);
			}

			// Načíst řádky z předaného pole?
			if (response.IsRowChangeMode(RowListChangeMode.AcceptRowItems) && response.ResultItems != null)
				this.AcceptFirstDataList(firstGId, response.ResultItems);
		}
		/// <summary>
		/// Vrátí soupis řádků, které se mají invalidovat
		/// </summary>
		/// <param name="response"></param>
		/// <returns></returns>
		private List<GID> _CrossDataGetInvalidateRows(InterGraphCurrentResponseCls response)
		{
			// Nejdřív jednoduché věci:
			if (!response.IsActiveFor(CurrentGraphCrossActivityMode.InvalidateRows))
				// Nic neinvalidovat?
				return null;
			if (response.ResultInvalidateRowList == null || response.ResultInvalidateRowList.Count == 0)
				// Není co invalidovat?
				return null;
			if (!response.IsActiveFor(CurrentGraphCrossActivityMode.InvalidateAllParents))
				// Není potřeba přidávat všechny parenty?
				return response.ResultInvalidateRowList;

			// Nyní složité věci: k daným řádkům mám přidat všechny jejich parenty:
			Dictionary<GID, object> invRows = new Dictionary<GID,object>();
			foreach (GID rowGId in response.ResultInvalidateRowList)
			{	// Daný řádek (GID) se může vyskytovat na více pozicích (když jeden sub node patří do více parents)
				List<int> nodes = this._NodeGetIdList(rowGId);   // Na kterých všech řádcích (nodech) je tento daný rowGID?
				if (nodes == null || nodes.Count == 0) continue; // Nikde (?)

				foreach (int nodeId in nodes)
				{	// Pro každý výskyt daného řádku najdu jeho celou cestu ke všem jeho parentům:
					List<GridNodeRowCls> nodeLine = this._NodeGetParentalLine(nodeId, true);
					foreach (GridNodeRowCls node in nodeLine)
					{	// Každý řádek (tj. daný plus jeho parenty) zkusím přidat do soupisu (jen 1x):
						if (!invRows.ContainsKey(node.GId))
							invRows.Add(node.GId, null);
					}
				}
			}

			// Vracím seznam unikátních GIDů:
			return new List<GID>(invRows.Keys);
		}
		/// <summary>
		/// Podle informací v response zajistí výběr elementů a určení aktivního řádku (první s vybraným elementem, nebo explicitně určený)
		/// </summary>
		/// <param name="e">Data o zdroji aktivity (graf, kde se něco stalo, a element + řádek)</param>
		/// <param name="activityMode">Aktivita this grafu při této události</param>
		/// <param name="response">Data pro řízení odpovědi tohoto grafu</param>
		/// <param name="elementDict">Odkaz na seznam elementů, které se mají označit jako vybrané v grafu</param>
		internal void CrossGraphResponseElements(GridGraphEventArgs e, CurrentGraphCrossActivityMode activityMode, InterGraphCurrentResponseCls response, ref Dictionary<GID, GID> elementDict)
		{
			response.ActiveRowIndex = -1;

			bool anyNodeIsChanged = false; // Příznak, že jsme provedli otevření / zavření některého nodu (pak dojde k vytvoření vizuálního listu)
			bool selectTopParent = response.IsActiveFor(CurrentGraphCrossActivityMode.SelectParentTopRow);  // Najít TopParent
			bool openTopParent = response.IsActiveFor(CurrentGraphCrossActivityMode.OpenActiveTreeNodes);   // Zajistit otevření nodu
			Dictionary<int, bool> findNodes = new Dictionary<int, bool>();

			List<DataPointerStr> currentElementList = response.ResultSelectElementList;
			if (currentElementList != null && currentElementList.Count > 0)
			{
				// Získali jsme pole pointerů na naše řádky/elementy, které jsou odpovídající ke vstupnímu elementu.
				// Naším úkolem je jednak zajistit zobrazení těchto elementů (otevřít nadřízené uzly),
				// a nalezení čísla prvního Top řádku pro toto zobrazení, podle konfigurace v activityMode:

				// Selectování elementů z odpovědi - do vstupního dictionary nebo do lokálního, podle aktivity:
				Dictionary<GID, GID> elemDict = null;
				if (response.IsActiveFor(CurrentGraphCrossActivityMode.SelectElements))
					// Pokud mám odpovídající elementy Selectovat, pak se navážu na předaný objekt a budu pracovat s ním:
					elemDict = elementDict;
				else
					// Odpovídající elementy nemám Selectovat, tak si vytvořím lokální objekt jen pro tuto metodu:
					elemDict = new Dictionary<GID, GID>();
				elemDict.Clear();

				// Pro každý vstupující element:
				foreach (DataPointerStr ptr in currentElementList)
				{
					// Zjistit nodeID jeho řádku, přidat element do elemDict, 
					// zajistit otevření nodu, přidat všechny nodeId (daný nebo TopParent) do findNodes:
					this._CrossGraphFindAddRowElement(ptr.Row, ptr.Element, elemDict, findNodes, selectTopParent, openTopParent, ref anyNodeIsChanged);
				}
			}

			// Explicitní řádek:
			bool selectExplicitRow = !response.ResultActivateRowGId.IsEmpty;
			if (selectExplicitRow)
			{
				// Zajistím si otevření tree k tomuto řádku (a jeho přidáním do findNodes i to, že zůstane otevřený i po CloseInactiveTreeNodes)
				this._CrossGraphFindAddRowElement(response.ResultActivateRowGId, GID.Empty, null, findNodes, selectTopParent, openTopParent, ref anyNodeIsChanged);
			}

			// Pokud mám vyhledávat a otevírat TopParent nody, a přitom nevybrané nody mám zavřít, 
			//  pak musím projít všechny TopNodes a ty nevybrané musím zavřít:
			if (selectTopParent && openTopParent && response.IsActiveFor(CurrentGraphCrossActivityMode.CloseInactiveTreeNodes))
				this.TreeNodeAllCollapse(findNodes, false, ref anyNodeIsChanged);

			// Pokud jsem přenastavil Node Expand/Close, tak musím vytvořit aktuální vizuální seznam:
			if (anyNodeIsChanged)
				this._CreateVisualList();

			// Musím najít číslo řádku, který se má aktivovat (z nalezených nodes je to ten, který má nejnižší číslo řádku):
			int rowIndex = -1;
			List<int> rowIndexList;
			if (selectExplicitRow)
			{
				rowIndexList = new List<int>();
				this._GetRowIndexList(response.ResultActivateRowGId, ref rowIndexList);
				rowIndex = this._CrossGraphFindLowIndex(rowIndexList);
			}
			if (rowIndex < 0 && findNodes.Count > 0)
			{
				rowIndexList = this.GetRowIndexList(findNodes.Keys);  // Z čísel NodeId vratí čísla indexů řádků
				rowIndex = this._CrossGraphFindLowIndex(rowIndexList);
			}
			response.ActiveRowIndex = rowIndex;
		}
		/// <summary>
		/// Zajistí přidání řádku a elementu do odpovídajících polí,
		/// zajistí otevření nodu pro daný řádek.
		/// </summary>
		/// <param name="row">GID řádku</param>
		/// <param name="element">GID elementu (může být Empty)</param>
		/// <param name="elemDict">Seznam elementů (pokud je GID elementu Empty, nic se do něj nedává)</param>
		/// <param name="findNodes">Seznam řádků, které se mají nechat otevřené, buď daný row, nebo jeho Top Parent</param>
		/// <param name="selectTopParent">Namísto řádku samého vybírat jeho Top Parent</param>
		/// <param name="openTopParent">Otevírat node od Top Parent k danému řádku</param>
		/// <param name="anyNodeIsChanged">Příznak změny otevření tree</param>
		private void _CrossGraphFindAddRowElement(GID row, GID element, Dictionary<GID, GID> elemDict, Dictionary<int, bool> findNodes, bool selectTopParent, bool openTopParent, ref bool anyNodeIsChanged)
		{
			// Vrátí seznam NodeID těch řádků, kde všude je zařazen (nemusí být aktuálně zobrazen!) řádek tohoto pointeru:
			List<int> nodeIdList = this._GetNodeIdList(row);
			if (nodeIdList == null || nodeIdList.Count == 0)
				return;              // Řádek daného GIDu není u nás nikde zobrazen => nezajímá nás.

			// Element našeho grafu: pokud je v seznamu v pointeru uveden element (není empty), 
			//  pak jej přidáme do ref pole elemDict (včetně indexu řádku):
			if (!element.IsEmpty)
			{
				if (elemDict.ContainsKey(element))
					return;          // Podruhé tu tentýž element (na jiném řádku !) nemá co dělat.
				elemDict.Add(element, row);
			}

			// Zpracovat nalezené nody, podle nastavení:
			foreach (int nodeId in nodeIdList)
			{
				// Najít top parenta a otevřít cestu z něj k našemu nodu:
				int findNodeId = -1;
				if (selectTopParent)
					// Pro každý nalezený node mám najít to parenta (a případně jej otevřít):
					findNodeId = this.GetTopParentNodeId(nodeId, openTopParent, ref anyNodeIsChanged);
				else
					// Nemám hledat top parenta: přidám přímo nalezený node:
					findNodeId = nodeId;

				if (findNodeId >= 0 && !findNodes.ContainsKey(findNodeId))
					findNodes.Add(findNodeId, true);
			}
		}
		/// <summary>
		/// Vrátí nejnižší index řádku z daného seznamu.
		/// </summary>
		/// <param name="rowList"></param>
		/// <returns></returns>
		private int _CrossGraphFindLowIndex(List<int> rowList)
		{
			if (rowList == null || rowList.Count <= 0) return -1;
			if (rowList.Count > 1)
				rowList.Sort();
			return rowList[0];
		}
		#endregion
		#region TVORBA EVENTARGS GridDataEventArgs, URČENÍ Target AKTIVITY GRAFU  (GraphDeclarationGetActivityMode())
		/// <summary>
		/// Vytvoří a vrátí EventArgs pro daný typ eventu.
		/// Do EventArgs opíše definici tohoto grafu a režim vyvolání akce pro tento event.
		/// Pokud vrátí null, pak se tento typ eventu nemá obsluhovat (což je definováno v deklaraci grafu).
		/// </summary>
		/// <param name="graphEvent">Druh eventu. Vloží se do argumentu, a podle něj se vybere odpovídající režim aktivity z this.GraphDeclarationData.</param>
		/// <param name="changeMode">Druh změny (co se mění a jak)</param>
		/// <returns></returns>
		protected GridDataEventArgs CreateDataEvent(GraphEventType graphEvent, GridEditingChangeMode changeMode)
		{
			TargetGraphCrossActivityMode targetMode = this.CrossGraphGetTargetMode(graphEvent);
			if (targetMode == TargetGraphCrossActivityMode.None)
				return null;

			GridDataEventArgs args = new GridDataEventArgs(this.GraphID, this.FirstGIdToLoad, this.DefaultGraphType, this._EditorInfo, graphEvent, targetMode, changeMode);
			return args;
		}
		/// <summary>
		/// Vytvoří a vrátí EventArgs pro daný typ eventu.
		/// Do EventArgs opíše definici tohoto grafu a režim vyvolání akce pro tento event.
		/// Pokud vrátí null, pak se tento typ eventu nemá obsluhovat (což je definováno v deklaraci grafu).
		/// </summary>
		/// <param name="graphEvent">Druh eventu. Vloží se do argumentu, a podle něj se vybere odpovídající režim aktivity z this.GraphDeclarationData.</param>
		/// <param name="changeMode">Druh změny (co se mění a jak)</param>
		/// <param name="changedRows">Řádky, jichž se změna týká</param>
		/// <param name="linkListChanged">Příznak změny linků</param>
		/// <returns></returns>
		protected GridDataEventArgs CreateDataEvent(GraphEventType graphEvent, GridEditingChangeMode changeMode, List<GID> changedRows, bool linkListChanged)
		{
			TargetGraphCrossActivityMode targetMode = this.CrossGraphGetTargetMode(graphEvent);
			if (targetMode == TargetGraphCrossActivityMode.None)
				return null;

			GridDataEventArgs args = new GridDataEventArgs(this.GraphID, this.FirstGIdToLoad, this.DefaultGraphType, this._EditorInfo, graphEvent, targetMode, changeMode, changedRows, linkListChanged);
			return args;
		}
		/// <summary>
		/// Vytvoří a vrátí EventArgs pro daný typ eventu.
		/// Do EventArgs opíše definici tohoto grafu a režim vyvolání akce pro tento event.
		/// Pokud vrátí null, pak se tento typ eventu nemá obsluhovat (což je definováno v deklaraci grafu).
		/// </summary>
		/// <param name="graphEvent">Druh eventu. Vloží se do argumentu, a podle něj se vybere odpovídající režim aktivity z this.GraphDeclarationData.</param>
		/// <param name="changeMode">Druh změny (co se mění a jak)</param>
		/// <returns></returns>
        protected GridDataEventArgs CreateDataEvent(GraphEventType graphEvent, GridEditingChangeMode changeMode, FunctionMenuItemRunArgs runArgs)
		{
			TargetGraphCrossActivityMode targetMode = this.CrossGraphGetTargetMode(graphEvent);
			if (targetMode == TargetGraphCrossActivityMode.None)
				return null;

            GridDataEventArgs args = new GridDataEventArgs(this.GraphID, this.FirstGIdToLoad, this.DefaultGraphType, this._EditorInfo, graphEvent, targetMode, changeMode,
                runArgs.ResultEditNewDataRows, runArgs.ResultEditChangedRows, runArgs.ResultEditDeletedRows, runArgs.ResultElementLinkListChanged);
			return args;
		}
		/// <summary>
		/// Vrátí režim TargetActivity pro this graf pro daný druh eventu.
		/// Režim aktivity čte z deklarace tohoto grafu, z property která odpovídá danému eventu (anebo vrací fixní hodnotu pro daný event).
		/// </summary>
		/// <param name="graphEvent"></param>
		/// <returns></returns>
		internal TargetGraphCrossActivityMode CrossGraphGetTargetMode(GraphEventType graphEvent)
		{
			switch (graphEvent)
			{
				case GraphEventType.MouseOver:
					return TargetGraphCrossActivityMode.OnThisPage;
				case GraphEventType.MouseClick:
					return this.GraphDeclarationData.TargetGraphActivityOnClick;
				case GraphEventType.MouseDoubleClick:
					return this.GraphDeclarationData.TargetGraphActivityOnDoubleClick;
				case GraphEventType.RowEnter:
					return this.GraphDeclarationData.TargetGraphActivityOnRowEnter;
				case GraphEventType.DataChanging:
					return TargetGraphCrossActivityMode.OnThisPage;
				case GraphEventType.DataChanged:
                case GraphEventType.FunctionChanged:
                    return this.GraphDeclarationData.TargetGraphActivityOnDataChanged;
                case GraphEventType.ReloadAllRows:
                    return TargetGraphCrossActivityMode.Anywhere;
				case GraphEventType.PageSwitch:
					return TargetGraphCrossActivityMode.Anywhere;
			}
			return TargetGraphCrossActivityMode.None;
		}
		/// <summary>
		/// Metoda zjistí, jaký druh aktivity pro current graf (CurrentGraphCrossActivityMode) máme provést,
		/// v případě události určitého typu (GraphEventType).
		/// Druh aktivity je uložen v deklaraci grafu (this.GraphDeclarationData.CurrentGraphActivityOn???).
		/// </summary>
		/// <param name="eventType">Typ události</param>
		/// <returns>Aktivia v případě této události</returns>
		internal CurrentGraphCrossActivityMode CrossGraphGetCurrentMode(GraphEventType eventType)
		{
			switch (eventType)
			{
				case GraphEventType.MouseOver:
					return CurrentGraphCrossActivityMode.None;
				case GraphEventType.MouseClick:
					return this.GraphDeclarationData.CurrentGraphActivityOnClick;
				case GraphEventType.MouseDoubleClick:
					return this.GraphDeclarationData.CurrentGraphActivityOnDoubleClick;
				case GraphEventType.RowEnter:
					return this.GraphDeclarationData.CurrentGraphActivityOnRowEnter;
				case GraphEventType.DataChanging:
					return this.GraphDeclarationData.CurrentGraphActivityOnDataChanging;
				case GraphEventType.DataChanged:
                case GraphEventType.FunctionChanged:
					return this.GraphDeclarationData.CurrentGraphActivityOnDataChanged;
				case GraphEventType.PageSwitch:
					return (this.GraphDeclarationData.CurrentGraphCallDataSourceOnActivate ? CurrentGraphCrossActivityMode.FindByDataSource : CurrentGraphCrossActivityMode.None);
				case GraphEventType.PageActivated:
					return (this.GraphDeclarationData.CurrentGraphCallDataSourceOnActivate ? CurrentGraphCrossActivityMode.FindByDataSource : CurrentGraphCrossActivityMode.None);
				case GraphEventType.PageDeactivated:
					return (this.GraphDeclarationData.CurrentGraphCallDataSourceOnActivate ? CurrentGraphCrossActivityMode.FindByDataSource : CurrentGraphCrossActivityMode.None);
                case GraphEventType.ReloadAllRows:
                    return CurrentGraphCrossActivityMode.ReloadAllRows;
				default:
					return CurrentGraphCrossActivityMode.None;
			}
		}
		#endregion
    }
}
